<script lang="tsx">
import { Skeleton } from '~/components/skeleton';
import { presetCols, type TColumn } from './column';
import ExpansionCol from './column/ExpansionCol.vue';

function getThSlotName(col: TColumn) {
  return `${String(col.key)}-th` as `${string}-th`;
}

function getTdSlotName(col: TColumn) {
  return `${String(col.key)}-td` as `${string}-td`;
}

export function TableLoading() {
  const bp = useAppBreakpoints();
  // style="mask-image: linear-gradient(180deg,#000,#0001)"
  return (
    <Skeleton class="grid grid-cols-5 gap-x-4 gap-y-8 lt-tablet:(grid-cols-3)">
      <Skeleton class="col-span-full -mb-3" type="rect" />
      {Array.from({ length: bp.ltTablet ? 12 : 30 }).map((_, i) => (
        <Skeleton key={i} class="col-span-1" type="rect" height={14} />
      ))}
    </Skeleton>
  );
}
</script>

<script setup lang="tsx" generic="D = any">
const props = defineProps<{
  indexId: string;
  columns: TColumn[];
  data: D[];
  rowClass?: string;
}>();
const emits = defineEmits<{
  clickRow: [row: D];
  clickData: [key: PropertyKey, row: D, event: MouseEvent];
}>();
defineSlots<{
  [key: ReturnType<typeof getThSlotName>]: (props: { col: TColumn }) => any;
  [key: ReturnType<typeof getTdSlotName>]: (props: {
    row: D;
    rowState?: typeof rowsState.value[string];
    toggleExpansion: typeof toggleExpansion;
  }) => any;
  expansion: (props: { row: D }) => any;
  footer: (props: { colNum: number }) => any;
}>();

const displayColNum = computed(() => props.columns.filter(col => col.show !== false).length);

// #region Row 的状态管理和操作
const rowsState = computed(() => {
  const state: Record<PropertyKey, { expanded: boolean }> = {};

  for (const row of props.data) {
    const key = (row as any)[props.indexId];
    state[key] = {
      expanded: false,
    };
  }

  return state;
});

function toggleExpansion(row: any) {
  const key = row[props.indexId];
  const rowState = rowsState.value[key];
  rowsState.value[key] = {
    ...rowState,
    expanded: !rowState?.expanded,
  };
  triggerRef(rowsState);
}
// #endregion
</script>

<template>
  <table class="table">
    <!-- 表头 -->
    <thead>
      <tr>
        <template v-for="col in props.columns" :key="col.key">
          <template v-if="col.show !== false">
            <th :class="[col.class, col.thClass]">
              <slot :name="getThSlotName(col)" :col="col">
                {{ col.name }}
              </slot>
            </th>
          </template>
        </template>
      </tr>
    </thead>

    <!-- 表体 -->
    <tbody>
      <template v-for="(row, i) of (props.data as any[])" :key="i">
        <!-- 数据 -->
        <tr :data-key="row[props.indexId]" :class="[props.rowClass]" @click="emits('clickRow', row)">
          <template v-for="col of props.columns" :key="col.key">
            <td
              v-if="col.show !== false"
              :class="[col.class, col.tdClass]"
              @click="emits('clickData', col.key, row, $event)"
            >
              <!-- 预设列 -->
              <ExpansionCol
                v-if="col.key === presetCols.expansion.config.key"
                :value="rowsState[row[props.indexId]]?.expanded"
                @update:value="toggleExpansion(row)"
              />
              <!-- 自定义列 -->
              <slot
                v-else
                :name="getTdSlotName(col)"
                :row="row"
                :rowState="rowsState[row[props.indexId]]"
                :toggleExpansion="toggleExpansion"
              >
                {{ row[col.key] }}
              </slot>
            </td>
          </template>
        </tr>
        <!-- 扩展 -->
        <tr
          v-if="$slots.expansion && rowsState[row[props.indexId]]?.expanded"
          class="expansion" :data-expand-key="row[props.indexId]"
        >
          <td :colspan="displayColNum">
            <slot name="expansion" :row="row" />
          </td>
        </tr>
      </template>
    </tbody>

    <!-- 表尾 -->
    <tfoot v-if="$slots.footer">
      <slot name="footer" :colNum="displayColNum" />
    </tfoot>
  </table>
</template>

<style lang="scss" scoped>
.table {
  --_padding-unit: var(--padding-unit, 4px);

  table-layout: auto;
  border-collapse: separate; // separate collapse
  border-spacing: 0 4px;
  margin: -4px 0; // 补偿 border-spacing，否则会导致表格上下有间隙
  width: 100%;
  text-align: left;

  tr {
    &[data-expand-key] td {
      background-color: theme('colors.sys.layer.c');
    }

    &:not(.expansion):hover td {
      background-color: theme('colors.sys.layer.d');
    }
  }

  th,
  td {
    padding: calc(var(--_padding-unit) * 3) calc(var(--_padding-unit) * 1);
    font-size: 14px;
    border: none !important;

    &:first-child {
      border-top-left-radius: 8px;
      border-bottom-left-radius: 8px;
      padding-left: calc(var(--_padding-unit) * 3);
    }

    &:last-child {
      padding-right: calc(var(--_padding-unit) * 3);
      border-top-right-radius: 8px;
      border-bottom-right-radius: 8px;
    }
  }

  th {
    color: theme('colors.sys.text.body');
    background-color: theme('colors.sys.layer.d');
    font-weight: 600;
  }

  td {
    border-bottom: 1px solid #26272e;
  }

  tr:has(input[type='checkbox']:checked) {
    background-color: theme('colors.sys.layer.d');
  }
}

.safe-style-list {
  --uno: 'w-10 relative';
}
</style>
